<template>
  <a-row v-if="user === 'admin'">
    <a-col :span="4">拖拽地图
      <a-switch v-model:checked="draggableWorld" checked-children="开" un-checked-children="关"/>
    </a-col>
    <a-col :span="4">拖拽城池
      <a-switch v-model:checked="draggableCity" checked-children="开" un-checked-children="关"/>
    </a-col>
    <a-col :span="4">拖拽路线
      <a-switch v-model:checked="draggableRoute" checked-children="开" un-checked-children="关"
                @change="operateRoute = draggableRoute ? false : operateRoute"/>
    </a-col>
    <a-col :span="4">操控路线
      <a-switch v-model:checked="operateRoute" checked-children="开" un-checked-children="关"
                @change="draggableRoute = operateRoute ? false : draggableRoute"/>
    </a-col>
  </a-row>
  <v3-drag-zoom-container
    ref="dragRef"
    style="width: 100%; height: 100%; background-color: #ccc; position: relative;"
    minZoom="1"
    maxZoom="2"
    :draggable="draggableWorld && !circleMove"
  >
    <img slot="title" src="/img/login.png"
         style="max-width: 100%; max-height: 100%; height: auto; display: block; border-style: none"
         alt="" draggable="false"/>
    <v3-drag-zoom-item
      v-for="city in cities"
      :position="city"
      :style="navigateCityStyle(city)"
      :draggable="draggableCity"
      :fixed-size="false"
      class="city"
      @onMove="pos => itemMove(pos, city)"
      @onMoveFinished="pos => itemMoveFinished(pos, city)"
      @click="navigateFun(city)"
    >{{ city.name }}
    </v3-drag-zoom-item>
    <svg class="line-svg" style="width: 100%; height: 100%" @click="handleClick"
         @mouseup="e => circleMouseup(e)"
         @mousemove="circleMousemove">
      <template v-for="(vector, rowIndex) in vectors" :key="`row-${rowIndex}`">
        <template v-for="(route, i) in vector.positions" :key="`line-${i}`">
          <line
            :class="navigateLineStyle(vector) ? 'navigate-line' : 'line'"
            :x1="route.depart.x + '%'"
            :y1="route.depart.y + '%'"
            :x2="route.dest.x + '%'"
            :y2="route.dest.y + '%'"
            @click.left="e => handleLineClick(e, vector, i)"
          />
          <text
            class="line-test"
            :x="((route.dest.x + route.depart.x) / 2) + '%'"
            :y="((route.dest.y + route.depart.y) / 2) + '%'"
          >
            {{ route.weight.toFixed(2) }}
          </text>
        </template>
        <template v-for="(route, i) in vector.positions" :key="`circle-${i}`">
          <circle
            v-if="i < vector.positions.length - 1"
            class="circle"
            :cx="route.dest.x + '%'"
            :cy="route.dest.y + '%'"
            r="0.3%"
            fill="white"
            stroke="#d7d7d7"
            stroke-width="1"
            style="z-index: 99"
            @mousedown="e => circleMousedown(e, vector, i)"
          />
        </template>
      </template>
      <template v-for="(arm, index) in army" :key="`army-${index}`">
        <circle
          class="circle"
          :cx="arm.x + '%'"
          :cy="arm.y + '%'"
          r="0.3%"
          fill="red"
          stroke="#d7d7d7"
          stroke-width="1"
          style="z-index: 99"
        />
      </template>
    </svg>
  </v3-drag-zoom-container>
  <!--线条编辑器-->
  <a-modal
    :footer="null"
    v-model:open="vectorDrawer"
    style="width: 12%; min-width: 200px;"
    :title="vectorDrawerTitle"
    @close="closeVectorDrawer"
  >
    <a-input-number addon-before="行军速度" min="0" v-model:value="speed" style="width: 100%;">
      <template #addonAfter>
        <SaveOutlined @click="saveRoute"/>
      </template>
    </a-input-number>
  </a-modal>
  <!--连接socket-->
  <a-modal
    cancelText=""
    :centered="true"
    :keyboard="false"
    :maskClosable="false"
    :ok-button-props="{ disabled: true }"
    v-model:open="loginDrawer"
    style="width: 13%; min-width: 310px;"
    title="请登录"
  >
    用户名：
    <a-input v-model:value="user" style="width: 10%; min-width: 200px;"/>
    <template #footer>
      <a-button key="submit" type="primary" @click="openSocket">确认</a-button>
    </template>
  </a-modal>
</template>
<script>
import { PlusOutlined, SaveOutlined } from '@ant-design/icons-vue'
import { cityList, updateCity } from '@/api/city'
import { updateVector, vectorList, warfare } from '@/api/vector'
import CoreConsts from '@/components/CoreConsts'
import { msgError, msgInfo, msgSuccess, msgWarn } from '@/utils/message'
import { urlConfig } from '@/utils/request'

export default {
  name: 'Index',
  components: {
    PlusOutlined,
    SaveOutlined
  },
  data() {
    return {
      // 城池列表
      cities: [],
      // 导航本
      vectors: [],
      // 是否可以拖拽世界地图
      draggableWorld: true,
      // 是否可以拖拽城池
      draggableCity: false,
      // 吃否可以拖拽路线节点
      draggableRoute: false,
      // 是否可以操作路线
      operateRoute: false,
      // 导航本弹窗开关
      vectorDrawer: false,
      // 导航本弹窗标题
      vectorDrawerTitle: '',
      // 标记当前导航本路线是否拖动中
      circleMove: false,
      // 当前操作中的导航本
      vector: null,
      // 当前操作中的导航本路线下标
      index: null,
      // 当前操作中的导航本路线行军速度
      speed: 0,
      // 导航
      navigateParam: {},
      navigateResult: [],
      socketClient: null,
      loginDrawer: false,
      user: null,
      army: {}
    }
  },
  setup() {
  },
  created() {
    // 获取城池
    cityList().then((resp) => {
      if (resp) {
        let { data, code, message } = resp;
        if (code === CoreConsts.SuccessCode) {
          this.cities = data
        } else {
          msgError(message || '加载世界失败');
        }
      }
      return {};
    }).catch(reason => reason);
    // 获取导航本
    vectorList().then((resp) => {
      if (resp) {
        let { data, code, message } = resp;
        if (code === CoreConsts.SuccessCode) {
          this.vectors = data
          // 计算路线距离
          this.vectors.forEach(v => v.positions.forEach(p => {
            const x = p.depart.x - p.dest.x
            const y = p.depart.y - p.dest.y
            p.weight = Math.sqrt(x * x + y * y) * p.speed
          }))
        } else {
          msgError(message || '加载世界失败');
        }
      }
      return {};
    }).catch(reason => reason);
    // 连接socket
    // this.openSocket()
    // 连接sse
    this.openSse()
  },
  methods: {
    // 城池拖拽
    itemMove(pos, city) {
      console.debug('itemMove', pos)
    },
    // 城池拖拽结束
    itemMoveFinished(pos, city) {
      console.debug('itemMoveFinished', pos, city)
      let x = city.x
      let y = city.y
      city.x = pos.x
      city.y = pos.y
      updateCity(city).then((resp) => {
        if (resp) {
          let { code, message } = resp;
          if (code === CoreConsts.SuccessCode) {
            msgSuccess(message || CoreConsts.OtherOperaSuccessMsg);
            this.calVector(city)
          } else {
            msgError(message || CoreConsts.OtherOperaFailMsg);
            city.x = x
            city.y = y
          }
        }
        return {};
      }).catch(reason => reason);
    },
    // 重新计算路线
    calVector(city) {
      this.vectors.forEach(v => {
        // 更新出发点导航本
        if (v.departName === city.name) {
          v.positions[0].depart.x = city.x
          v.positions[0].depart.y = city.y
        }
        // 更新目的点导航本
        else if (v.destName === city.name) {
          v.positions.at(-1).dest.x = city.x
          v.positions.at(-1).dest.y = city.y
        }
      })
    },
    // svg图点击
    handleClick(e) {
      console.debug('handleClick', e)
    },
    // svg图线条点击（打开抽屉弹窗）
    handleLineClick(e, vector, i) {
      // 打开弹窗
      if (this.operateRoute) {
        console.debug('handleLineClick-operateRoute', e, vector, i)
        this.vectorDrawerTitle = vector.name
        this.vectorDrawer = true
        this.vector = vector
        this.index = i
        this.speed = this.vector.positions[i].speed
      }
      // 添加节点
      if (this.draggableRoute) {
        console.debug('handleLineClick-draggableRoute', e, vector, i)
        this.vector = vector
        const depart = vector.positions[i].depart;
        const dest = vector.positions[i].dest;
        const x = (dest.x + depart.x) / 2
        const y = (dest.y + depart.y) / 2
        // 增加一条线路，当前鼠标位置为出发点，原线路目的点作为新的目的点
        this.vector.positions.splice(i + 1, 0, { depart: { x: x, y: y }, dest: { x: dest.x, y: dest.y }, speed: 1 })
        // 当前鼠标位置 为 当前路线的结束点
        dest.x = x
        dest.y = y
        this.updateVectorFun()
      }
    },
    // 保存行军速度
    saveRoute() {
      console.debug('saveRoute',
        'vector.speed', this.vector.positions[this.index].speed,
        'speed', this.speed
      )
      this.vector.positions[this.index].speed = this.speed
      this.updateVectorFun()
    },
    // 关闭抽屉弹窗
    closeVectorDrawer() {
      this.vector = null
      this.index = null
    },
    // 路线节点鼠标按下
    circleMousedown(event, vector, i) {
      if (this.draggableRoute) {
        console.debug('circleMousedown', event.x, event.y, event.view.innerWidth, event.view.innerHeight)
        this.circleMove = true
        this.vector = vector
        this.index = i
        this.vector.ex = event.x;
        this.vector.ey = event.y;
      }
    },
    // 路线节点鼠标移动
    circleMousemove(event) {
      if (this.draggableRoute && this.circleMove && !!this.vector) {
        console.debug('circleMousemove',
          // 'event.x:', event.x ,
          // 'event.y:', event.y,
          // 'event.view.innerWidth:', event.view.innerWidth,
          // 'event.view.innerHeight:', event.view.innerHeight,
          // 'offsetX:', (event.x - this.vector.ex) / event.view.innerWidth,
          // 'offsetY:', (event.y - this.vector.ey) / event.view.innerHeight
        )
        const dest = this.vector.positions[this.index].dest;
        const depart = this.vector.positions[this.index + 1].depart;
        depart.x += (event.x - this.vector.ex) / event.view.innerWidth * 100
        depart.y += (event.y - this.vector.ey) / event.view.innerHeight * 100
        dest.x = depart.x
        dest.y = depart.y
        this.vector.ex = event.x;
        this.vector.ey = event.y;
      }
    },
    // 路线节点鼠标弹起
    circleMouseup() {
      if (this.draggableRoute && this.circleMove && !!this.vector) {
        this.updateVectorFun()
      }
      this.vector = null
      this.index = null
      this.circleMove = false
    },
    // 保存导航本
    updateVectorFun() {
      updateVector(this.vector).then((resp) => {
        if (resp) {
          let { code, message } = resp;
          if (code === CoreConsts.SuccessCode) {
            msgSuccess(message || CoreConsts.OtherOperaSuccessMsg);
          } else {
            msgError(message || CoreConsts.OtherOperaFailMsg);
            city.x = x
            city.y = y
          }
        }
        return {};
      }).catch(reason => reason);
    },
    // 导航
    navigateFun(city) {
      if (this.draggableCity || this.draggableRoute || this.operateRoute) {
        this.navigateParam = {}
        return
      }
      if (null == this.navigateParam.departName) {
        this.navigateParam.departName = city.name
      } else {
        if (null == this.navigateParam.destName) {
          this.navigateParam.destName = city.name
        } else {
          this.navigateParam = {}
        }
      }
      this.navigateResult = []
      if (null != this.navigateParam.departName && null != this.navigateParam.destName) {
        if (this.navigateParam.departName === this.navigateParam.destName) {
          msgWarn('起点与终点不能相同')
          this.navigateParam.departName = null
          this.navigateParam.destName = null
          return;
        }
        // 开始导航
        // navigate(this.navigateParam).then((resp) => {
        //   if (resp) {
        //     let { data, code, message } = resp;
        //     if (code === CoreConsts.SuccessCode) {
        //       this.navigateResult = data
        //     } else {
        //       msgError(message || CoreConsts.OtherOperaFailMsg);
        //       this.navigateParam.destName = city.name
        //     }
        //   }
        //   return {};
        // }).catch(reason => reason);
        warfare(this.navigateParam).then((resp) => {
          if (resp) {
            let { data, code, message } = resp;
            if (code === CoreConsts.SuccessCode) {
              msgSuccess(message)
            } else {
              msgError(message || CoreConsts.OtherOperaFailMsg);
              this.navigateParam.destName = city.name
            }
          }
          return {};
        }).catch(reason => reason);
      }
    },
    // 导航变更城池样式
    navigateCityStyle(city) {
      let bgColor = '#d7d7d7'
      if (this.navigateResult.indexOf(city.name) > -1) {
        bgColor = '#ff7c7c'
      }
      if (this.navigateParam.departName === city.name || this.navigateParam.destName === city.name) {
        bgColor = 'red'
      }
      return {
        'width': '1.8rem',
        'height': '1.8rem',
        'line-height': '1.8rem',
        'font-size': '0.5rem',
        'border-radius': '18px',
        'background-color': bgColor
      }
    },
    // 导航变更路线样式
    navigateLineStyle(vector) {
      return this.navigateResult.indexOf(vector.departName) > -1 && this.navigateResult.indexOf(vector.destName) > -1
    },
    // 连接socket
    openSocket() {
      if (null == this.user) {
        this.user = null
        this.loginDrawer = true;
        return;
      }
      let socketClient = new WebSocket(urlConfig.getWsBaseURI() + `/ws?token=${this.user}`)
      socketClient.onopen = event => {
        console.log('onopen', event)
        this.loginDrawer = false
      }
      socketClient.onerror = event => {
        console.log('onerror', event)
        msgError('连接失败，检查用户名是否正确')
      }
      socketClient.onmessage = event => {
        this.handle(JSON.parse(event.data))
      }
      socketClient.onclose = event => {
        this.loginDrawer = true;
      }
    },
    // 连接sse
    openSse() {
      this.$sse.create(urlConfig.getSseUrl() + '/sse/countDown')
        .on('message', (msg) => {
          // 处理接收到的消息
          this.handle(JSON.parse(msg))
        })
        .on('error', (err) => {
          console.error('Failed to parse or lost connection:', err)
          // 重新连接
          setTimeout(() => {
            this.openSse()
          }, 1000); // 1秒后重新连接
        })
        .connect()
        .catch((err) => {
          console.error('Failed make initial connection:', err)
          msgError('sse 连接失败')
          // 重新连接
          setTimeout(() => {
            this.openSse()
          }, 5000); // 5秒后重新连接
        })
    },
    // 处理长连接消息
    handle(aliveMessage) {
      const t = aliveMessage['t']
      switch (aliveMessage['type']) {
        case 0: // 连接成功
          msgInfo(t.tip)
          break
        case 1: // 行军
          this.army[t.name] = t.position
          break
        case 2: // 到达
          if (!!t.name && !!this.army[t.name]) {
            delete this.army[t.name];
          }
          msgSuccess(t['warfareName'])
          break
        case 3: // 相遇
          t.names.forEach(e => {
            if (!!this.army[e]) {
              console.log(this.army, e)
              delete this.army[e];
            }
          })
          msgSuccess('[' + t['warfareNames'].join('], [') + ']相遇')
          break
      }
    }
  },
  activated() {
  },
  deactivated() {
  }
}
</script>

<style scoped>
.city {
  font-size: 12px;
  text-align: center;

  cursor: pointer;
  align-items: center; /* 垂直居中 */
  justify-content: center; /* 水平居中 */
  z-index: 90;
}

.line-svg {
  position: absolute;
  top: 0;
  left: 0;
}

.line {
  stroke: darkgreen;
  stroke-linecap: round;
  stroke-width: 1;
  z-index: 80;
  cursor: pointer;
}

.navigate-line {
  stroke: green;
  stroke-linecap: round;
  stroke-width: 2;
  z-index: 80;
  cursor: pointer;
}

.line:hover + .line-test, .navigate-line:hover + .line-test {
  display: block;
}

.line-test {
  display: none;
  font-size: 10px;
  fill: lightcyan;
}

.circle {
  stroke-linecap: round;
  z-index: 100;
  cursor: pointer;
}
</style>
